﻿using System;
using System.Runtime.Serialization.Formatters.Binary;

namespace Lyon.MemoryShares
{
    /// <summary>
    /// 内存交换信道
    /// </summary>
    abstract public class MemoryChannel : IDisposable
    {
        NamedWaitLock lockServer;
        NamedWaitLock lockStart;
        NamedWaitLock lockWrite;
        NamedWaitLock lockRead;
        NamedWaitLock lockEnd;

        string _ChannelName;
        BinaryFormatter formatter = new BinaryFormatter();
        MemorySharing _Memory;
        byte[] _buffer;
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="channelName"></param>
        protected MemoryChannel(string channelName)
        {
            _ChannelName = channelName;
            _buffer = new byte[1024 * 1024];
            _Memory = new MemorySharing(channelName, _buffer.Length);
            lockServer = new NamedWaitLock(_ChannelName+".Server");
            lockStart = new NamedWaitLock(_ChannelName + ".Start");
            lockWrite = new NamedWaitLock(_ChannelName + ".Write");
            lockRead = new NamedWaitLock(_ChannelName + ".Read");
            lockEnd = new NamedWaitLock(_ChannelName + ".End");
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            lockEnd.Dispose();
            lockRead.Dispose();
            lockWrite.Dispose();
            lockStart.Dispose();
            lockServer.Dispose();
            _Memory.Dispose();
        }

        protected object OnTryReceive(int timeout)
        {
            var watch = System.Diagnostics.Stopwatch.StartNew();
            while (_Memory.Count == -1 && watch.ElapsedMilliseconds < timeout)
            {
            }
            if (_Memory.Count == -1)
                return null;

            return OnReceive();
        }
        protected object OnReceive()
        {
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                int readCount = 0;
                do
                {
                    BeginRead();
                    readCount = _Memory.Read(_buffer, 0, _buffer.Length);
                    _Memory.Clear();
                    EndRead();
                    stream.Write(_buffer, 0, readCount);
                }
                while (readCount == _buffer.Length);
                stream.Seek(0, System.IO.SeekOrigin.Begin);
                return formatter.Deserialize(stream);
            }
        }
        protected void OnAccept()
        {
            lockStart.WaitLock();
            lockWrite.WaitLock();
            //lockServer.WaitOtherUnlock();
            lockServer.WaitLock();
            lockServer.WaitLock();
            lockServer.WaitUnlock();
            
        }
        private void BeginRead()
        {
            lockStart.WaitUnlock();
            lockEnd.WaitLock();
            lockWrite.WaitUnlock();
            lockRead.WaitLock();
            lockWrite.WaitLock();
        }
        private void EndRead()
        {
            lockEnd.WaitUnlock();
            lockStart.WaitLock();
            lockRead.WaitUnlock();
        }
        protected void OnSend(object value)
        {
            using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
            {
                formatter.Serialize(stream, value);
                int dataLength = (int)stream.Length;

                int noFullWriteCount = dataLength % _Memory.Capacity;
                int fullWriteCount = dataLength - noFullWriteCount;

                stream.Seek(0, System.IO.SeekOrigin.Begin);
                for (int i = 0; i < fullWriteCount; i += _Memory.Capacity)
                {
                    stream.Read(_buffer, 0, _Memory.Capacity);
                    BeginWrite();
                    _Memory.Write(_buffer, 0, _Memory.Capacity);
                    EndWrite();
                }
                stream.Read(_buffer, 0, noFullWriteCount);

                BeginWrite();
                _Memory.Write(_buffer, 0, noFullWriteCount);
                EndWrite();
            }
        }
        protected void OnConnect()
        {
            lockEnd.WaitLock();
            lockRead.WaitLock();
            lockServer.WaitUnlock();
        }
        private void BeginWrite()
        {
            lockEnd.WaitUnlock();
            lockStart.WaitLock();
            lockWrite.WaitLock();
        }
        private void EndWrite()
        {
            lockRead.WaitUnlock();
            lockWrite.WaitUnlock();
            lockEnd.WaitLock();
            lockStart.WaitUnlock();
            lockRead.WaitLock();
        }
    }
    /// <summary>
    /// 内存服务端信道
    /// </summary>
    public class MemoryServer : MemoryChannel
    {
        public MemoryServer(string channelName)
            : base(channelName)
        {
        }

        public object TryReceive(int timeout)
        {
            return OnTryReceive(timeout);
        }
        public object Receive()
        {
            return base.OnReceive();
        }
        public void Accept()
        {
            base.OnAccept();
        }

        
    }
    /// <summary>
    /// 内存客户端信道
    /// </summary>
    public class MemoryClient : MemoryChannel
    {
        public MemoryClient(string channelName)
            : base(channelName)
        {
        }

        public void Send(object value)
        {
            base.OnSend(value);
        }
        public void Connect()
        {
            base.OnConnect();
        }
    }
}